package edos.prm.task;

import java.util.HashMap;
import java.util.Set;

import edos.prm.activity.Activity;
import edos.prm.actor.Actor;
import edos.prm.actor.Actor.PrmActor;
import edos.prm.artifact.UnregisteredArtifactType;
import edos.prm.engine.PRM;
import edos.prm.process.Process;
import edos.prm.process.ProcessAction;
import edos.prm.process.Process.PrmProcess;
import edos.prm.process.ProcessAction.NativeProcess;
import edos.prm.project.Project;
import edos.prm.role.RoleException;
import edos.prm.task.Task.PrmTask;
import edos.prm.util.Time;
import edos.prm.util.VersionNumber;

/**
 * A {@code TaskManager} is repsonsible for the management of tasks by the
 * PRM engine.
 * 
 * @author Ciaran
 */
public interface TaskManager extends Activity {

	/**
	 * Returns the task that is currently executing in the PRM.
	 * 
	 * @return the currently active task.
	 */
	public Task currentTask();
	
	/**
	 * Create a new task to execute a process.
	 * 
	 * @param actor the actor on whose behalf the task runs.
	 * @param project the project in which the task runs
	 * @param process the process that gets executed
	 * @return the newly created task in CREATED state.
	 * throws RoleException if the caller does not have the right to this
	 * operation.
	 */
	public Task newTask(Actor actor, Project project, Process process);
	
	/**
	 * Return the tasks that are running for the given actor in the specified
	 * project.
	 * 
	 * @param actor the actor running tasks.
	 * @param project the project which is being queried
	 * @return a set of tasks.
	 */
	public Set<Task> getTasks(Actor actor, Project project);
		
	/**
	 * Start executing a task.
	 * 
	 * @param task the task to execute
	 * @throws RoleException if the caller does not have the needed role
	 * @throws IllegalArgumentException if the task's status is not CREATED
	 */
	public void execute(Task task);
	
	public final static class PrmTaskManager implements TaskManager {

		private static HashMap<Thread, Task> threadToTaskMap;
		private static PrmTaskManager instance;
		
		static {
			threadToTaskMap = new HashMap<Thread, Task>();
			instance = new PrmTaskManager();
			Task defaultTask = instance.newTask(Actor.ROOT_ACTOR,
					Project.ROOT_PROJECT, Process.ROOT_PROCESS);
			Task.PrmTask.setDefaultTask(defaultTask);
		}

		private PrmTaskManager() {}
		
		public static PrmTaskManager getInstance() {
			return instance;
		}
		
		public void execute(Task task) {
			try {
				task.execute();
			} catch (RoleException e) {
				e.printStackTrace();
			}
		}

		public  Set<Task>  getTasks(Actor actor, Project project) {
			// TODO Auto-generated method stub
			return null;
		}

		public Task newTask(Actor actor, Project project, Process process) {
			Task task = new Task.PrmTask(actor, project, process);
			try {
				if ( !actor.equals(PrmActor.ROOT_ACTOR) )
					PRM.getArtifactManager().registerArtifact(task);
			} catch (UnregisteredArtifactType e) {
				e.printStackTrace();
			}
			PrmProcess pp = (PrmProcess)process;
			ProcessAction.NativeProcess pa = (NativeProcess) pp.getDeclaredActions();
			Thread t = pa.getThread();
			threadToTaskMap.put(t, task);
			return task;
		}

		public Time getCreationDate() {
			// TODO Auto-generated method stub
			return null;
		}

		public String getDescription() {
			return new String("Default PRM Task Manager");
		}

		public VersionNumber getVersion() {
			return PRM.getPRMVersion();
		}

		public static Task getTask(Thread thread) {
			return threadToTaskMap.get(thread);
		}

		public static void kickoff() throws RoleException {
			PrmTask.DefaultTask.execute();
		}

		public Task currentTask() {
			Thread thread = Thread.currentThread();
			Task task = threadToTaskMap.get(thread);
			return task;
		}
	}
}
